;
;  Program:  XLATE2
;  Author:  Richard Conn
;  Derivation:  Disassembled XLATE.COM of Cromemco's CDOS and Modified
;		into XLATE2; XLATE.COM was Version 2.40
;  Version:  1.1
;  Date:  21 July 82
;  Previous Versions:  1.0 (3 May 82)
;
;	XLATE2 inputs an Intel-Standard 8080 Assembly Language Source File
; and converts it into a Zilog-Standard Z80 Assembly Language Source File.
;
VERS	EQU	11	;VERSION NUMBER

;
;  USE ZILOG MNEMONICS AND ABSOLUTE SEGMENTS
;
	.Z80
	ASEG

;
;  CP/M CONSTANTS
;
WBOOT	EQU	0
BDOS	EQU	5
DEFFCB	EQU	5CH
FCB2	EQU	6CH

;
;  START OF PROGRAM
;
	ORG	100H

	CALL	HCHECK		;CHECK FOR HELP REQUEST
	LD	SP,OBUFLPOS	;INIT STACK PTR
	CALL	INIT		;INIT THE PROGRAM
LOOP:
	CALL	BUILDLINE	;BUILD THE NEXT INPUT LINE
	CALL	PROCESSOPS	;CONVERT THE OP CODES
	JR	LOOP

;
;  MAIN PROCESSING MODULE
;
PROCESSOPS:
	CALL	GETOP	;EXTRACT THE NEXT OP CODE
	JP	Z,FLUSHLINE	;IF NONE, FLUSH
;
	LD	HL,OCS1	;PROCESS OP CODE SET 1
	LD	BC,10	;10 CHARS/DUAL ENTRY (OLD OP = 5, NEW OP = 5)
	CALL	CMPOP	;SCAN FOR MATCH IN INLN BUFFER
	JP	Z,DOOCS1	;PROCESS IF FOUND
;
	LD	HL,OCS2	;PROCESS OP CODE SET 2
	LD	BC,10	;10 CHARS/DUAL ENTRY
	CALL	CMPOP	;SCAN FOR MATCH
	JP	Z,DOOCS2	;PROCESS
;
	LD	HL,OCS3	;PROCESS OP CODE SET 3
	LD	BC,10	;10 CHARS/DUAL ENTRY
	CALL	CMPOP	;SCAN FOR MATCH
	JP	Z,DOOCS3	;PROCESS
;
	LD	HL,OCS4	;PROCESS (EXTENDED RET) OP CODE SET 4
	LD	BC,5	;5 CHARS/SINGLE ENTRY
	CALL	CMPOP	;SCAN FOR MATCH
	CALL	Z,DOOCS4	;CONVERT INTO STANDARD RET FORMS IF MATCH
;
	LD	HL,RETS	;PROCESS (NORMAL RET) OP CODE SET 5
	LD	BC,5	;5 CHARS/SINGLE ENTRY
	CALL	CMPOP	;SCAN FOR MATCH
	JP	Z,DORETS	;PROCESS
;
	LD	HL,CALLS	;PROCESS (CALL) OP CODE SET 6
	LD	BC,5	;5 CHARS/SINGLE ENTRY
	CALL	CMPOP	;SCAN FOR MATCH
	JP	Z,DOCALLS	;PROCESS
;
	LD	HL,JMPS	;PROCESS (JMP) OP CODE SET 7
	LD	BC,5	;5 CHARS/SINGLE ENTRY
	CALL	CMPOP	;SCAN FOR MATCH
	JP	Z,DOJMPS	;PROCESS
;
	LD	HL,OCS8	;PROCESS OP CODE SET 8
	LD	BC,12	;12 CHARS/DUAL ENTRY
	CALL	CMPOP	;SCAN FOR MATCH
	JP	Z,DOOCS8	;PROCESS
;
;  NO MATCH IN OP CODE SETS -- PASS TARGET OP CODE AS IS
;
	LD	B,5	;5 CHARS IN TARGET
	LD	HL,TARGOP	;POINT TO TARGET
POPS1:
	LD	A,(HL)	;GET CHAR
	CP	' '	;END OF OP?
	JR	Z,POPS2	;OUTPUT TAB CHAR IF SO
	CP	9	;END OF OP?
	JR	Z,POPS2	;OUTPUT TAB CHAR IF SO
	CALL	DOUTCHAR	;OUTPUT OP CHAR
	INC	HL	;PT TO NEXT
	DJNZ	POPS1	;CONTINUE FOR 5 CHARS MAX
POPS2:
	LD	A,9	;END OP WITH <TAB>
	CALL	DOUTCHAR	;OUTPUT TO DISK
;
;  COPY REST OF INPUT LINE AS-IS
;
COPYARGS:
	LD	HL,(INLNPTR)	;PT TO NEXT CHAR
CARGS1:
	LD	C,0
CARGS2:
	LD	A,(HL)	;GET CHAR
	CP	' '	;END OF OPERANDS?
	JR	Z,CARGS4	;SKIP WHITE SPACE AND OUTPUT REST IF SO
	CP	9	;END OF OPERANDS?
	JR	Z,CARGS4	;SKIP WHITE SPACE AND OUTPUT REST IF SO
	CP	0DH	;END OF LINE?
	JR	Z,FLUSHLINE	;FLUSH IF SO
	CP	';'	;BEGINNING OF COMMENT = END OF OPERANDS?
	JR	Z,CARGS5	;COPY REST IF SO
	CP	''''	;SINGLE QUOTE?
	JR	NZ,CARGS3
	DEC	C
	JR	Z,CARGS3
	LD	C,1
CARGS3:
	CALL	DOUTCHAR	;OUTPUT CHAR IN A TO DISK
	INC	HL	;PT TO NEXT
	JR	CARGS2
CARGS4:
	PUSH	HL
	CALL	SKIPWHITE	;SKIP TO NEXT NON-WHITE CHAR
	POP	HL
	CP	0DH	;END OF LINE?
	JR	Z,FLUSHLINE	;FLUSH IF SO
	CP	';'	;COMMENT?
	JR	Z,CARGS5	;PROCESS COMMENT IF SO
	CALL	OUTWHITE	;OUTPUT A TAB
	JR	CARGS2		;RESTART PROCESSING
CARGS5:
	DEC	C
	INC	C
	JR	NZ,CARGS3
	CALL	SKIPWHITE
	LD	B,41
CARGS6:
	LD	A,(OBUFLPOS)	;CHECK POSITION IN OUTPUT LINE
	CP	B
	JR	NC,FLUSHLINE
	DEC	A	;BACK UP IN OUTPUT LINE
	AND	0F8H	;ARTIFICALLY TAB
	ADD	A,9
	CP	B
	JR	Z,FLUSHLINE
	JR	C,CARGS7
	LD	A,' '
	JR	CARGS8
CARGS7:
	LD	A,9
CARGS8:
	CALL	DOUTCHAR
	JR	CARGS6
;
;  WRITE REST OF INLN TO DISK
;
FLUSHLINE:
	CALL	OUTSTR
	LD	A,1	;RESET POSITION COUNTER
	LD	(OBUFLPOS),A
	RET
;
;  PRINT PDOT FOR EVERY TEN LINES
;
PDOT:
	LD	A,(LCOUNT)	;GET LINE COUNT
	DEC	A	;COUNT DOWN
	LD	(LCOUNT),A	;PUT LINE COUNT
	RET	NZ	;DONE IF NOT ZERO
	LD	A,'.'	;PRINT PDOT
	CALL	PCHAR
	LD	A,10	;RESET COUNT
	LD	(LCOUNT),A
	LD	A,(NLCOUNT)	;NEW LINE?
	DEC	A
	LD	(NLCOUNT),A
	RET	NZ
	LD	DE,CRLFSTR	;PRINT NEW LINE
	CALL	PMSG
	LD	A,60	;RESET COUNTER
	LD	(NLCOUNT),A
	RET
;
;  OUTPUT STRING PTED TO BY HL TO DISK (STRING ENDS IN 0)
;
OUTSTR:
	LD	A,(HL)	;GET CHAR
	AND	A	;DONE?
	RET	Z	;RET IF SO
	CALL	DOUTCHAR
	INC	HL	;PT TO NEXT CHAR
	JR	OUTSTR
;
;  OUTPUT ALL <SP> AND <TAB> CHARS FOUND UNTIL A NON-<SP> AND NON-<TAB>
;    ENCOUNTERED
;
OUTWHITE:
	LD	A,(HL)	;GET CHAR
	CP	' '	;<SP>?
	JR	Z,OW1	;OUTPUT IT
	CP	9	;<TAB>?
	RET	NZ	;DONE IF NOT
OW1:
	CALL	DOUTCHAR	;OUTPUT CHAR IN A TO DISK
	INC	HL	;PT TO NEXT CHAR
	JR	OUTWHITE	;CONTINUE
;
;  EXTRACT OP CODE FOR INPUT LINE AND PLACE IN BUFFER
;
GETOP:
	LD	HL,INLN	;PT TO INPUT LINE
	LD	A,(HL)	;GET 1ST CHAR IN LINE
	CP	' '	;NO LABEL?
	JR	Z,GOP3	;SKIP TO OP CODE
	CP	9	;NO LABEL?
	JR	Z,GOP3	;SKIP TO OP CODE
	CP	';'	;COMMENT?
	RET	Z	;DONE IF SO
;
;  LINE BEGINS WITH A LABEL -- PROCESS IT
;
GOP1:
	LD	C,0	;SET LABEL CHAR CNT
GOP2:
	LD	A,(HL)	;GET NEXT CHAR OF LABEL
	CP	':'	;END OF LABEL?
	JR	Z,GOP4
	CP	9	;END OF LABEL?
	JR	Z,GOP5
	CP	0DH	;END OF LABEL AND NO FURTHER PROCESSING?
	JR	Z,GOP5
	CP	';'	;END OF LABEL AND NO FURTHER PROCESSING?
	JR	Z,GOP5
	CP	' '	;END OF LABEL?
	JR	Z,GOP5
	CALL	DOUTCHAR	;OUTPUT LABEL CHAR TO DISK
	INC	HL	;PT TO NEXT CHAR
	INC	C	;INCR LABEL CHAR CNT
	JR	GOP2
;
;  NO LABEL -- SKIP TO OP CODE
;
GOP3:
	CALL	SKIPWHITE	;SKIP OVER WHITE SPACE
	PUSH	HL
	CALL	FTODLM
	CP	':'
	POP	HL
	JR	Z,GOP1
	JR	GOP7
;
;  END OF LABEL BY ':' CHAR
;
GOP4:
	INC	HL	;SKIP ':'
	CALL	DOUTCHAR	;OUTPUT THE ':'
	LD	A,(HL)	;CHECK FOR EOL
	CP	0DH	;DON'T DOUBLE NEW LINE (SKIP NEW LINE AFTER GOP6)
	JR	Z,GOP8	;JUST CONTINUE PROCESSING WITH NO TAB
	JR	GOP6	;NOT NEW LINE, SO PROCESS FOR NEW LINE IF LONG LABEL
;
;  OUTPUT ':' AT END OF LABEL
;
GOP5:
	LD	A,':'	;OUTPUT THE ':'
	CALL	DOUTCHAR
;
;  SEE IF LABEL IS LESS THAN 7 CHARS LONG
;    IF <7, THEN TERMINATE WITH <TAB>; IF >6, THEN NEW LINE AND <TAB>
;
GOP6:
	LD	A,C	;GET LABEL CHAR CNT
	CP	7	;LESS THAN 7?
	JR	C,GOP7	;JUST TAB IF LESS THAN 7
	LD	A,0DH	;<CR>
	CALL	DOUTCHAR
	LD	A,0AH	;<LF>
	CALL	DOUTCHAR
;
;  OUTPUT <TAB> AFTER LABEL TO DISK
;
GOP7:
	LD	A,9	;<TAB>
	CALL	DOUTCHAR
;
;  SKIP TO OP CODE FIELD AND EXTRACT IT IF PRESENT
;
GOP8:
	CALL	SKIPWHITE	;SKIP TO OP CODE FIELD
	LD	A,(HL)	;GET FIRST NON-WHITE CHAR
	CP	';'	;NO OP CODE IF COMMENT
	RET	Z	;DONE IF COMMENT
	CP	0DH	;NO OP CODE IF EOL
	RET	Z	;DONE IF EOL
	LD	(ILTOP),HL	;SAVE PTR TO TARGET OP CODE
	LD	B,5	;5 CHARS MAX IN OP CODE
	LD	DE,TARGOP	;COPY TO TARGOP BUFFER
	CALL	COPYTODELIM	;COPY UNTIL DELIMITER ENCOUNTERED
	CALL	SKIPWHITE	;SKIP OVER WHITE SPACE WHICH FOLLOWS
	LD	(INLNPTR),HL	;SAVE PTR
	SUB	A
	INC	A	;A=1 AND NZ
	RET
;
;  COMPARE OP CODE PTED TO BY HL WITH TARGET OP CODE; RET WITH Z SET IF
;    MATCH, NZ IF NO MATCH
;
CMPOP:
	LD	A,(HL)	;NO OP CODE TO COMPARE?
	AND	A	;A=0 IF SO
	JR	Z,CMPOP1	;FAILURE IF SO
	PUSH	BC
	LD	B,5	;COMPARE 5 BYTES
	LD	DE,TARGOP	;PT TO TARGET OP CODE
	CALL	COMPHLDE	;COMPARE
	POP	BC
	RET	Z	;DONE IF MATCH
	ADD	HL,BC	;PT TO NEXT OP CODE IN TABLE
	JR	CMPOP
CMPOP1:
	INC	A	;A=1 AND NZ
	RET
;
;  PROCESS OP CODES IN SET 1 -- OPERAND AND COMMENTS FIELDS ARE UNCHANGED
;    HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DISK
;
DOOCS1:
	CALL	OUTNEWOP5CH	;OUTPUT NEW OP CODE
	JP	COPYARGS	;COPY OPERAND AND COMMENT FIELDS AS-IS
;
;  OUTPUT 2ND 5-CHAR-MAX OP CODE FIELD PTED TO BY HL TO DISK AND END IN <TAB>
;
OUTNEWOP5CH:
	LD	BC,5	;SKIP FIRST 5 CHARS
	ADD	HL,BC	;PT TO 2ND 5-CHAR FIELD
;
;  ENTRY PT TO COPY 5-CHAR-MAX FIELD PTED TO BY HL
;
ONO5C0:
	LD	B,5
ONO5C1:
	LD	A,(HL)	;GET NEXT CHAR
	CP	' '	;<SP>?
	JR	Z,ONO5C2	;DONE IF SO
	CP	9	;<TAB>?
	JR	Z,ONO5C2	;DONE IF SO
	CALL	DOUTCHAR	;OUTPUT CHAR TO DISK
	INC	HL	;PT TO NEXT
	DJNZ	ONO5C1	;COUNT DOWN
ONO5C2:
	LD	A,9	;OUTPUT <TAB> TO DISK
	JP	DOUTCHAR	;OUTPUT TO DISK
;
;  PROCESS OP CODES IN SET 2 - OPERAND IS 1 REG OR '(HL)'
;    HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DISK
;
DOOCS2:
	CALL	OUTNEWOP5CH	;OUTPUT NEW 5-CHAR-MAX OP CODE
	LD	HL,(INLNPTR)	;PT TO OPERAND FIELD
ATHLCHECK:
	LD	A,(HL)	;CHECK FOR '(HL)' REFERENCE
	CP	'M'	;TAKES THE FORM OF 'M' IN 8080 MNEMONICS
	JP	NZ,CARGS1	;OUTPUT NORMALLY IF NOT
	INC	HL	;PT TO CHAR AFTER
	PUSH	HL	;SAVE PTR
	LD	HL,ATHL	;OUTPUT '(HL)'
	CALL	OUTSTR	;OUTPUT TO DISK
	POP	HL	;GET PTR
	JP	CARGS1	;PROCESS REST OF LINE NORMALLY
ATHL:
	DB	'(HL)',0
;
;  PROCESS OP CODES IN SET 3 - OPERAND IS BC, DE, HL, OR PSW REG PAIR
;    HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DISK
;
DOOCS3:
	CALL	OUTNEWOP5CH	;OUTPUT NEW OP CODE
RPCHECK:
	LD	HL,(INLNPTR)	;PT TO OPERAND FIELD
	PUSH	HL	;SAVE PTR
	LD	A,(HL)	;GET OPERAND
	CP	'B'	;FOR BC?
	JR	Z,PRBC	;OUTPUT BC IF SO
	CP	'D'	;FOR DE?
	JR	Z,PRDE	;OUTPUT DE IF SO
	CP	'H'	;FOR HL?
	JR	Z,PRHL	;OUTPUT HL IF SO
	CP	'P'	;FOR PSW?
	JR	NZ,L0309	;OUTPUT WHATEVER'S THERE IF NOT
	INC	HL	;MAKE SURE IT IS 'PSW'
	LD	A,(HL)
	CP	'S'
	JR	NZ,L0309	;OUTPUT WHAT'S THERE IF NOT
	INC	HL
	LD	A,(HL)
	CP	'W'
	JR	NZ,L0309	;OUTPUT WHAT'S THERE IF NOT
	POP	HL		;IT IS 'PSW', SO CLEAR STACK AND PT
	INC	HL		; ... TO CHAR AFTER 'PSW'
	INC	HL
	PUSH	HL
	LD	HL,AFSTR	;PRINT 'AF'
	JR	PRREGPAIR	;DO PRINT
PRBC:
	LD	HL,BCSTR	;PRINT 'BC'
	JR	PRREGPAIR
PRDE:
	LD	HL,DESTR	;PRINT 'DE'
	JR	PRREGPAIR
PRHL:
	LD	HL,HLSTR	;PRINT 'HL'
PRREGPAIR:
	CALL	OUTSTR	;PRINT STRING PTED TO BY HL AND MAKE HL ON STACK
	POP	HL	; ... PT TO NEXT CHAR
	INC	HL
	PUSH	HL
L0309:
	POP	HL	;PRINT WHATEVER OTHER OPERAND IT IS
	JP	CARGS1	;PRINT THE OPERAND
AFSTR:
	DB	'AF',0
BCSTR:
	DB	'BC',0
DESTR:
	DB	'DE',0
HLSTR:
	DB	'HL',0
;
;  PROCESS OP CODE SET 4 - EQ, NE, LT, GE RETS, CALLS, AND JMPS
;    HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DISK
;
DOOCS4:
	LD	A,(TARGOP+1)	;LOOK AT 2ND LETTER OF TARGET OP
	LD	HL,ZFLG	;PREP FOR ZERO
	CP	'E'	;IF 'E', THEN FORM IS 'EQ'
	JR	Z,ZCPUT	;CHANGE FORM TO 'XZ ', WHERE X=R,C,J
	LD	HL,NZFLG	;PREP FOR NOT ZERO
	CP	'N'	;IF 'N', THEN FORM IS 'NE'
	JR	Z,ZCPUT
	LD	HL,CFLG	;PREP FOR CARRY
	CP	'L'	;IF 'L', THEN FORM IS 'LT'
	JR	Z,ZCPUT
	LD	HL,NCFLG	;FORM MUST BE 'GE', SO NO CARRY
ZCPUT:
	LD	A,(HL)	;GET FIRST CHAR
	LD	(TARGOP+1),A	;STORE IT
	INC	HL	;PT TO 2ND CHAR
	LD	A,(HL)	;GET IT
	LD	(TARGOP+2),A	;STORE IT
	RET
ZFLG:
	DB	'Z '
NZFLG:
	DB	'NZ'
CFLG:
	DB	'C '
NCFLG:
	DB	'NC'
;
;  PROCESS OP CODE SET 5 -- RETURN FORMS
;    HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DISK
;
DORETS:
	LD	HL,RETSTR	;PT TO STR TO COPY
	CALL	COPY5	;COPY WITH OPTIONAL COND
	JP	COPYARGS	;COPY REST OF OPERAND FIELD AND COMMENTS AS-IS
RETSTR:
	DB	'RET  ',0
DOCALLS:
	LD	HL,CALLSTR
	JR	CP5WITHCOMMA	;COPY AND FOLLOW WITH COMMA
CALLSTR:
	DB	'CALL ',0
DOJMPS:
	LD	HL,JPSTR	;FALL THRU TO DO JP FORMS
;
;  COPY STRING AT HL FOLLOWED BY CONDITION CODE, A COMMA, AND REST OF
;    OPERAND FIELD
;
CP5WITHCOMMA:
	CALL	COPY5
	LD	A,','
	CALL	DOUTCHAR	;OUTPUT COMMA TO DISK
	JP	COPYARGS	;COPY REST OF OPERAND FIELD
JPSTR:
	DB	'JP   ',0
;
;  COPY 5-CHAR-MAX STRING PTED TO BY HL FOLLOWED BY <TAB> AND 2-CHAR COND
;
COPY5:
	CALL	ONO5C0	;COPY 5-CHAR-MAX STRING PTED TO BY HL
	LD	A,(TARGOP+1)	;OUTPUT FIRST CHAR OF COND
	CALL	DOUTCHAR
	LD	A,(TARGOP+2)	;OUTPUT 2ND CHAR OF COND IF NOT <SP>
	CP	' '
	RET	Z
	JP	DOUTCHAR
;
;  PROCESS OP CODE SET 8 - THIS TABLE CONTAINS THE SERVICE ROUTINE ADR
;    EMBEDDED IN IT AFTER EACH OP CODE PAIR;
;    HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DISK
;
DOOCS8:
	PUSH	HL	;SAVE PTR TO OLD (1ST) OP
	LD	BC,10	;PT TO ADR OF SERVICE ROUTINE
	ADD	HL,BC
	LD	C,(HL)	;BC=ROUTINE ADDRESS
	INC	HL
	LD	B,(HL)
	POP	HL	;PT TO OLD (1ST) OP
	PUSH	BC	;ROUTINE ADDRESS ON STACK
	RET		;JMP TO ROUTINE
;
;  THIS CONVERTS 'DAD <RP>' TO 'ADD HL,<RP>'
;
DO81:
	CALL	OUTNEWOP5CH	;OUTPUT 'ADD<TAB>'
	LD	HL,DO81S	;OUTPUT 'HL,'
	CALL	OUTSTR
	JP	RPCHECK	;OUTPUT <REG PAIR>
DO81S:
	DB	'HL,',0
;
;  THIS CONVERTS 'ADD R' TO 'ADD A,R'
;    AND 'ADC R' TO 'ADC A,R'
;    AND 'SBC R' TO 'SBC A,R'
;
DO82:
	CALL	OUTNEWOP5CH	;OUTPUT THE 'IN<TAB>'
	LD	HL,DO82S	;OUTPUT 'A,'
	JP	DO8F1	;04C7H
DO82S:
	DB	'A,',0
;
;  THIS CONVERTS 'LDA <ADR>' TO 'LD A,(<ADR>)'
;    AND 'IN <ADR>' TO 'IN A,(<ADR>)'
;
DO83:
	CALL	OUTNEWOP5CH
	LD	HL,DO83S
	JR	OUTCLP
DO83S:
	DB	'A,(',0
;
;  THIS CONVERTS 'LDAX <RP>' TO 'LD A,(<RP>)'
;
DO84:
	CALL	OUTNEWOP5CH	;OUTPUT OP CODE
	LD	HL,(INLNPTR)	;PT TO OPERAND
	LD	A,(HL)	;GET 1ST CHAR OF OPERAND
	CP	'B'	;BC REG PAIR?
	JR	Z,DO841	;PROCESS IT
	CP	'D'	;DE REG PAIR?
	JR	Z,DO842	;PROCESS IT
	JP	CARGS1	;SOMETHING FUNNY -- PROCESS NORMALLY
DO841:
	LD	HL,DO841S
	JP	DO8D3
DO842:
	LD	HL,DO842S
	JP	DO8D3
DO841S:
	DB	'A,(BC)',0
DO842S:
	DB	'A,(DE)',0
;
;  THIS CONVERTS 'LHLD <ADR>' TO 'LD HL,(<ADR>)'
;
DO85:
	CALL	OUTNEWOP5CH
	LD	HL,DO85S
;
;  THIS OUTPUTS THE STRING PTED TO BY HL, OUTPUTS THE REST OF THE OPERAND
;    FIELD, OUTPUTS A CLOSING ')', AND OUTPUTS THE REST OF THE INPUT LINE
;
OUTCLP:
	CALL	OUTSTR	;01F9H
	CALL	OUTOPER	;04D5H
	LD	A,')'	;29H
	CALL	DOUTCHAR	;0631H
	JP	CARGS1	;0198H
DO85S:
	DB	'HL,(',0
;
;  THIS CONVERTS 'MOV R,R' TO 'LD R,R'
;
DO86:
	CALL	OUTNEWOP5CH
	LD	HL,(INLNPTR)	;PT TO 1ST CHAR OF OPERAND FIELD
	LD	A,(HL)	;GET IT
	CP	'M'	;CONVERT 'M' TO '(HL)'?
	JR	NZ,DO862	;NO CONVERSION NECESSARY
	PUSH	HL
	LD	HL,ATHL	;OUTPUT '(HL)'
	CALL	OUTSTR
	POP	HL
;
;  OUTPUT ',' FOLLOWED BY '(HL)' OR 'R'
;
DO861:
	INC	HL	;OUTPUT COMMA AND THEN 2ND R
	LD	A,(HL)	;GET COMMA
	CALL	DOUTCHAR
	INC	HL	;PT TO 2ND R
	JP	ATHLCHECK	;OUTPUT '(HL)' OR R
;
;  OUTPUT 'R,' FOLLOWED BY '(HL)' OR 'R'
;
DO862:
	CALL	DOUTCHAR	;OUTPUT 'R'
	JR	DO861	;OUTPUT REST
;
;  THIS CONVERTS 'PCHL' TO 'JP<TAB>(HL)'
;
DO88:
	CALL	OUTNEWOP5CH
	LD	HL,ATHL	;OUTPUT THE '(HL)'
	JP	DO8F1
;
;  THIS CONVERTS 'RST N' TO 'RST NNH'
;
DO89:
	CALL	OUTNEWOP5CH
	LD	HL,DO89S
	JP	DO8F1
DO89S:
	DB	'8*',0	;MULTIPLY RESTART NUMBER BY 8 FOR Z80
;
;  THIS CONVERTS 'SHLD <ADR>' TO 'LD (<ADR>),HL'
;
DO8A:
	CALL	OUTNEWOP5CH
	LD	A,'('	;OUTPUT OPENING '('
	CALL	DOUTCHAR
	CALL	OUTOPER	;OUTPUT OPERAND
	PUSH	HL
	LD	HL,DO8AS	;OUTPUT '),HL'
	JR	DO8C2
DO8AS:
	DB	'),HL',0
;
;  THIS CONVERTS 'SPHL' TO 'LD SP,HL'
;
DO8B:
	CALL	OUTNEWOP5CH
	LD	HL,DO8BS
	JR	DO8F1
DO8BS:
	DB	'SP,HL',0
;
;  THIS CONVERTS 'STA <ADR>' TO 'LD (<ADR>),A'
;    AND 'OUT <ADR>' TO 'OUT (<ADR>),A'
;
DO8C:
	CALL	OUTNEWOP5CH
	LD	A,'('	;OUTPUT '('
;
;  THIS OUTPUTS '<OPERAND>),A'
;
DO8C1:
	CALL	DOUTCHAR	;OUTPUT CHAR IN A
	CALL	OUTOPER	;OUTPUT OPERAND FIELD
	PUSH	HL
	LD	HL,DO8CS	;OUTPUT '),A'
DO8C2:
	CALL	OUTSTR	;OUTPUT STRING PTED TO BY HL
	POP	HL	;CLEAR STACK
	JP	CARGS1	;OUTPUT REST OF INPUT LINE
DO8CS:
	DB	'),A',0
;
;  THIS CONVERTS 'STAX <RP>' TO 'LD (<RP>),A'
;
DO8D:
	CALL	OUTNEWOP5CH
	LD	HL,(INLNPTR)	;PT TO 1ST CHAR OF OPERAND
	LD	A,(HL)	;GET IT
	CP	'B'	;BC REG PAIR?
	JR	Z,DO8D1	;OUTPUT IT IF SO
	CP	'D'	;DE REG PAIR?
	JR	Z,DO8D2	;OUTPUT IT IF SO
	JP	CARGS1	;ELSE, OUTPUT WHAT'S THERE
DO8D1:
	LD	HL,DO8D1S
	JR	DO8D3
DO8D2:
	LD	HL,DO8D2S
DO8D3:
	CALL	OUTSTR
	LD	HL,(INLNPTR)	;PT TO AFTER 'B' OR 'D'
	INC	HL
	JP	CARGS1
DO8D1S:
	DB	'(BC),A',0
DO8D2S:
	DB	'(DE),A',0
;
;  THIS CONVERTS 'XCHG' TO 'EX DE,HL'
;
DO8E:
	CALL	OUTNEWOP5CH
	LD	HL,DO8ES
	JR	DO8F1
DO8ES:
	DB	'DE,HL',0
;
;  THIS CONVERTS 'XTHL' TO 'EX (SP),HL'
;
DO8F:
	CALL	OUTNEWOP5CH
	LD	HL,DO8FS
DO8F1:
	CALL	OUTSTR	;01F9H
	JP	COPYARGS	;0195H
DO8FS:
	DB	'(SP),HL',0
;
;  OUTPUT REST OF OPERAND FIELD UP TO WHITE SPACE BEFORE ENDING COMMENT
;    OR END OF LINE
;
OUTOPER:
	LD	HL,(INLNPTR)	;PT TO NEXT CHAR IN INPUT LINE BUFFER
OOL1:
	LD	A,(HL)	;GET NEXT CHAR
	CP	';'	;BEGINNING OF COMMENT?
	JR	Z,OOL2	;CHECK FOR REST OF OPERAND
	CP	0DH	;END OF LINE?
	JR	Z,OOL2	;CHECK FOR REST OF OPERAND
	INC	HL	;CONTINUE UNTIL EITHER COMMENT OR EOL FOUND
	JR	OOL1
OOL2:
	DEC	HL	;BACK UP (OVER WHITE SPACE?)
	LD	A,(HL)	;GET CHAR
	CP	' '	;WHITE?
	JR	Z,OOL2	;CONTINUE BACKING
	CP	9	;WHITE?
	JR	Z,OOL2	;CONTINUE BACKING
	INC	HL	;PT TO FIRST WHITE CHAR
	EX	DE,HL	;SAVE PTR IN DE
	LD	HL,(INLNPTR)	;PT TO START OF SCAN
OOL3:
	LD	A,D	;ALL OF OPERAND FIELD FLUSHED?
	CP	H	;CHECK FOR PTR MATCH
	JR	NZ,OOL4	;NO MATCH, SO FLUSH NEXT CHAR
	LD	A,E	;REST OF MATCH?
	CP	L
	RET	Z	;DONE IF ALL MATCH
OOL4:
	LD	A,(HL)	;OUTPUT OPERAND CHAR TO DISK
	CALL	DOUTCHAR
	INC	HL	;PT TO NEXT OPERAND CHAR
	JR	OOL3	;CONTINUE UNTIL OPERAND ALL OUT
;
;  THE FOLLOWING TURNS ON VARIOUS MESSAGES FOR MANUAL TRANSLATION
;
DO91:
	LD	A,9	;ENDIFS
	LD	(XLT1ON),A	;STORE <TAB> TO ENABLE
	JR	DO941
DO92:
	LD	A,9	;INCLUDES
	LD	(XLT2ON),A
	JR	DO941
DO93:
	LD	A,9	;LISTS
	LD	(XLT3ON),A
	JR	DO941
DO94:
	LD	A,9	;MACROS
	LD	(XLT4ON),A
DO941:
	CALL	OUTNEWOP5CH	;OUTPUT NEW CODE
	LD	A,0DH	;TURN ON PRINTED ERR MESSAGE
	LD	(ERR5ON),A	;TURN ON FLAG BY STARTING WITH <CR>
	JP	COPYARGS	;COPY REST OF CODE
;
;  THE FOLLOWING CHECKS FOR THE SPECIFICATION OF A HELP OPTION AND
;    PRINTS THE HELP MESSAGE IF SO
;
HCHECK:
	LD	A,(DEFFCB+1)	;GET FIRST CHAR OF FILE NAME
	CP	'/'		;OPTION?
	RET	NZ		;NO HELP REQUESTED IF NOT OPTION
	LD	DE,HEADER	;PRINT PROGRAM BANNER
	CALL	PMSG
	LD	DE,HMSG1	;PRINT HELP MESSAGE
	CALL	PMSG
	LD	C,1		;GET ANY CHAR
	CALL	BDOS
	LD	DE,HMSG2	;PRINT REST OF HELP MESSAGE
	CALL	PMSG
	POP	DE		;CLEAR STACK
	RET			;RETURN TO CP/M
;
;  THE FOLLOWING INITIALIZES THE PROGRAM FOR EXECUTION
;
INIT:
	LD	DE,HEADER	;PRINT PROGRAM BANNER
	CALL	PMSG
	LD	A,10		;INIT PDOT PRINT (LINE) COUNT
	LD	(LCOUNT),A
	LD	A,60		;INIT NEW LINE PRINT COUNT
	LD	(NLCOUNT),A
	LD	A,1		;INITIALIZE OUTPUT BUFFER LINE POSITION
	LD	(OBUFLPOS),A
	CALL	MAKEFNS		;SET UP FILE NAMES
	CALL	OPENIN		;OPEN INPUT FILE
	CALL	OPENOUT		;OPEN OUTPUT FILE
	LD	HL,FHDR		;OUTPUT '.Z80' AND 'ASEG' TO MAC FILE
INIT1:
	LD	A,(HL)		;GET CHAR
	OR	A		;DONE?
	JR	Z,INIT2
	CALL	DOUTCHAR	;OUTPUT TO DISK
	INC	HL		;PT TO NEXT
	JR	INIT1
INIT2:
	LD	A,(FCB2+1)	;2ND FILE NAME PRESENT?
	CP	' '		;<SP> IF NOT
	RET	NZ		;DONE IF SO
	XOR	A		;A=0
	LD	(OCS4),A	;TURN OFF WEIRD OP CODE SCAN (REQ, ETC)
	LD	(NOXLT),A	;TURN OFF SCAN FOR ENT, NAME, RAM, ROG
	LD	(NOXLT2),A	;TURN OFF SCAN FOR IFC, ICL, MAC, LST
	RET
;
;  SET UP FILE NAMES
;
MAKEFNS:
	LD	HL,DEFFCB	;COPY INPUT FILE NAME FROM COMMAND
	LD	DE,FCBASM	;INTO THIS FCB FOR USE
	LD	BC,9		;9 BYTES
	LDIR			;COPY
	LD	A,(HL)		;FILE TYPE SPECIFIED?
	CP	' '		;NONE IF <SP>
	JR	Z,MFN1
	LD	BC,3		;3 MORE BYTES
	LDIR
MFN1:
	LD	HL,FCB2+1	;2ND FILE SPECIFIED?
	LD	A,(HL)		;GET FIRST BYTE OF FILE NAME
	DEC	HL		;PT TO FIRST BYTE OF FCB
	CP	' '		;NO 2ND FILE NAME?
	JR	NZ,MFN2		;SKIP RELOAD OF HL IF THERE IS A 2ND FILE NAME
	LD	HL,DEFFCB	;COPY FILE NAME INTO OUTPUT FCB
MFN2:
	LD	DE,FCBZ80	;OUTPUT FCB
	LD	BC,9		;9 BYTES
	LDIR			;COPY
	LD	HL,FCB2+9	;PT TO FILE TYPE
	LD	A,(HL)		;CHECK FOR A FILE TYPE
	CP	' '		;NONE IF <SP>
	JR	Z,MFN3
	LD	BC,3		;THERE IS ONE, SO COPY IT OVER
	LDIR
MFN3:
	LD	DE,PRFNM1	;PRINT PART 1 OF FILE NAME MESSAGE
	CALL	PMSG
	LD	HL,FCBASM	;PRINT NAME OF SOURCE FILE
	CALL	PRFNAME
	LD	DE,PRFNM2	;PRINT PART 2 OF FILE NAME MESSAGE
	CALL	PMSG
	LD	HL,FCBZ80	;PRINT NAME OF DESTINATION FILE
	CALL	PRFNAME
	LD	DE,CRLFSTR	;END LINE
	CALL	PMSG
	RET
;
;  PRINT FILE NAME MESSAGE
;
PRFNAME:
	LD	A,(HL)		;GET DISK NUMBER
	ADD	A,'@'		;ADD IN ASCII BIAS
	CALL	PCHAR
	LD	A,':'		;PRINT COLON
	CALL	PCHAR
	INC	HL		;PT TO FIRST CHAR OF FILE NAME
	LD	B,8		;8 CHARS
	CALL	PRFNC
	LD	A,'.'		;DOT
	CALL	PCHAR
	LD	B,3		;3 CHARS
	CALL	PRFNC
	RET
PRFNC:
	LD	A,(HL)		;GET NEXT CHAR
	INC	HL		;PT TO NEXT
	CALL	PCHAR		;PRINT CHAR
	DJNZ	PRFNC
	RET

;
;  OPEN INPUT FILE FOR PROCESSING
;
OPENIN:
	LD	DE,FCBASM	;OPEN FILE FOR INPUT
	LD	C,0FH
	CALL	BDOS
	CP	0FFH		;ERROR?
	JR	Z,OIERR		;ABORT WITH ERROR MESSAGE IF SO
	LD	A,80H		;INIT CHAR COUNT FOR BUFFER
	LD	(IBUFCNT),A
	RET
OIERR:
	LD	DE,ERR2		;INPUT FILE ERROR MESSAGE
	JP	ENDERR		;ABORT
;
;  OPEN FILE FOR OUTPUT
;
OPENOUT:
	LD	DE,FCBZ80	;OPEN OUTPUT FILE
	LD	C,0FH
	CALL	BDOS
	CP	0FFH		;ERROR?
	JR	NZ,OOERR2	;ABORT IF NO ERROR (OVERWRITE OLD FILE)
OPENO1:
	LD	DE,FCBZ80	;ELSE CREATE OUTPUT FILE
	LD	C,16H
	CALL	BDOS
	CP	0FFH		;ERROR?
	JR	Z,OOERR1
	LD	DE,FCBZ80	;NOW OPEN OUTPUT FILE (REDUNDANT WITH MAKE)
	LD	C,0FH
	CALL	BDOS
	LD	A,80H		;INIT COUNT OF BYTES REMAINING
	LD	(OBUFBACKCNT),A	;SET COUNT
	LD	HL,OBUF		;INIT ADDRESS OF NEXT BYTE
	LD	(OBUFPTR),HL	;SET PTR
	RET
OOERR1:
	LD	DE,ERR3	;DISK FULL
	JP	ENDERR	;ABORT ERROR
OOERR2:
	LD	DE,ERR4	;ATTEMPT TO OVERWRITE EXISTING FILE
	CALL	PMSG
	LD	C,1	;GET RESPONSE
	CALL	BDOS
	CALL	CAPS	;CAPITALIZE
	CP	'Y'	;CONTINUE IF YES
	LD	DE,ERR4A	;PREP FOR ABORT
	JP	NZ,ENDERR	;ABORT ERROR
	LD	DE,CRLFSTR	;NEW LINE
	CALL	PMSG
	LD	DE,FCBZ80	;DELETE OLD FILE
	LD	C,19		;BDOS DELETE FILE
	CALL	BDOS
	JR	OPENO1		;CREATE NEW FILE AND CONTINUE
;
;  CHECK TO SEE IF CHAR PTED TO BY HL IS A DELIMITER AND FLUSH CHARS UNTIL
;    IT IS; RET WITH ZERO FLAG SET WHEN DONE
;
FTODLM:				;Flush TO DeLiMiter
	PUSH	BC
	CALL	DLIMSCAN	;DO SCAN
	POP	BC
	RET	Z		;MATCH, SO ABORT
	INC	HL		;PT TO NEXT CHAR
	JR	FTODLM		;CONTINUE SCAN
;
;  COPY (HL) TO (DE) FOR B BYTES OR UNTIL A DELIMITER IS ENCOUNTERED
;
COPYTODELIM:
	LD	C,B	;LET BC=OLD B (FOR LDI INSTR)
	LD	B,0
	PUSH	BC	;SAVE REGS
	PUSH	DE
	PUSH	HL
	CALL	SPFILL	;FILL DESTINATION BUFFER WITH SPACES (PTED TO BY DE)
	POP	HL	; ... AND C BYTES LONG
	POP	DE
	POP	BC
CTD1:
	PUSH	BC	;SAVE COUNT
	CALL	DLIMSCAN	;SCAN FOR DELIMITER IF ENCOUNTERED
	POP	BC
	RET	Z	;DONE IF SO
	LDI		;COPY NEXT CHAR INTO DESTINATION BUFFER
	JP	PO,DLIMSCAN	;FINAL DELIMITER SCAN IF DONE
	JR	CTD1
;
;  ADVANCE BUFFER POINTER HL UNTIL NON-WHITE (NON-<SP>, NON-<TAB>)
;    ENCOUNTERED
;
SKIPWHITE:
	LD	A,(HL)	;GET CHAR
	CP	' '	;<SP>?
	JR	Z,SKPWH1	;SKIP IF SO
	CP	9	;<TAB>?
	RET	NZ	;DONE IF NOT
SKPWH1:
	INC	HL	;PT TO NEXT CHAR
	JR	SKIPWHITE
;
;  CHECK TO SEE IF CHAR PTED TO BY HL IS A DELIMITER
;
DLIMSCAN:
	PUSH	DE
	EX	DE,HL	;PT TO CHAR WITH DE
	LD	HL,DLIMS	;PT TO TABLE OF DELIMITERS
	CALL	DELIMCHS	;DO SCAN IN GENERAL
	EX	DE,HL	;PT TO CHAR WITH HL
	LD	A,(HL)	;GET CHAR IN A
	POP	DE
	RET
;
;  TABLE OF VALID DELIMITERS
;
DLIMS:
	DB	1,1	;SCAN 1 BYTE AT A TIME, AND SKIP 1 BYTE IF NO MATCH
	DB	','	;DELIMITERS ...
	DB	':'
	DB	'+'
	DB	'-'
	DB	'/'
	DB	'*'
	DB	' '
	DB	')'
	DB	';'
	DB	0DH
	DB	9	; ... TO HERE
	DB	0	;END OF TABLE
;
;  SCAN FOR DELIMITER -- RETURN WITH NZ IF NOT FOUND OR PT TO DELIMITER
;    WITH Z IF FOUND; ON INPUT, TABLE PTED TO BY HL WITH 1ST 2 BYTES
;    GIVING NUMBER OF BYTES TO CHECK AND NUMBER OF BYTES TO SKIP, RESP,
;    ON EACH PARTIAL SCAN
;
DELIMCHS:
	CALL	SPCHSCAN	;DO SCAN OF TABLE
	RET	NZ	;NOT FOUND
	LD	C,B	;CHAR OFFSET COUNT IN BC
	LD	B,0
	ADD	HL,BC	;PT TO CHAR
	SUB	A	;SET ZERO FLAG
	RET
;
;  SCAN SPECIAL CHAR TABLE PTED TO BY HL FOR STRING PTED TO BY DE;
;    NUMBER OF SIGNIFICANT BYTES TO SCAN AS FIRST ENTRY IN TABLE,
;    NUMBER OF BYTES TO SKIP ON FAILURE AS 2ND ENTRY IN TABLE;
;    TABLE ENDS IN A BINARY 0
;
SPCHSCAN:
	LD	B,(HL)	;B=NUMBER OF BYTES TO SCAN
	INC	HL
	LD	C,(HL)	;C=NUMBER OF BYTES TO SKIP ON FAILURE
	INC	HL	;PT TO FIRST VALID BYTE IN TABLE
;
;  MAIN SCANNING LOOP
;
SPCH1:
	LD	A,(HL)	;CHECK FOR END OF TABLE
	AND	A	;ZERO?
	JR	Z,SPCH2	;DONE IF SO
	CALL	COMPHLDE	;DO COMPARE
	RET	Z	;RETURN IF MATCH
	LD	A,C	;POINT TO NEXT TABLE ENTRY
	CALL	ADDHLA	;HL=HL+(SIZE OF TABLE ENTRY)
	JR	SPCH1
;
;  NO MATCH -- RETURN NZ
;
SPCH2:
	INC	A	;A=1 AND NZ
	RET
;
;  COMPARE CHARS PTED TO BY DE WITH THAT PTED TO BY HL FOR B BYTES
;    RET WITH ZERO FLAG SET IF COMPLETE MATCH, NZ IF NO MATCH;
;    HL, DE, BC NOT AFFECTED
;
COMPHLDE:
	PUSH	HL	;SAVE REGS
	PUSH	DE
	PUSH	BC
CMPHD1:
	LD	A,(DE)	;GET DE CHAR
	CP	(HL)	;COMPARE TO HL CHAR
	JR	NZ,CMPHD2	;NO MATCH
	INC	HL	;PT TO NEXT
	INC	DE
	DJNZ	CMPHD1	;COUNT DOWN -- ZERO FLAG SET ON END
CMPHD2:
	POP	BC	;RESTORE REGS
	POP	DE
	POP	HL
	RET
;
;  HL=HL+A
;
ADDHLA:
	ADD	A,L	;DO IT
	LD	L,A
	RET	NC
	INC	HL
	RET
;
;  FILL MEMORY PTED TO BY DE WITH SPACES FOR BC BYTES
;
SPFILL:
	LD	A,' '	;<SP>
	LD	(DE),A	;STORE FIRST <SP>
	LD	H,D	;MAKE HL PT TO 1ST <SP>
	LD	L,E
	INC	DE	;DE PTS TO NEXT BYTE
	DEC	BC	;BC IS 1 BYTE LESS
	LDIR		;COPY USING LDIR
	RET
;
;  OUTPUT CHAR IN A TO DISK FILE
;
DOUTCHAR:
	PUSH	HL		;SAVE REGS
	PUSH	DE
	PUSH	BC
	PUSH	AF
	LD	HL,(OBUFPTR)	;GET ADDRESS OF NEXT CHAR POS IN OUT BUFFER
	LD	(HL),A		;STORE CHAR INTO OUT BUFFER
	CP	9		;CHECK FOR TAB
	JR	NZ,NOTABOUT	;NOT TAB -- DON'T UPDATE COUNT
	LD	A,(OBUFLPOS)	;TAB -- UPDATE LOCATION IN LINE
	DEC	A		;A=OUT BUFFER LINE POSITION - 1
	AND	0F8H		;MASK FOR TAB
	ADD	A,9		;AND ADD 9
	JR	DOUT1
;  NOT A TAB -- JUST INCR POSITION COUNT
NOTABOUT:
	LD	A,(OBUFLPOS)	;GET ADDRESS OF NEXT CHAR POS IN OUT BUFFER
	INC	A		;ADD 1 TO IT
DOUT1:
	LD	(OBUFLPOS),A	;UPDATE OUT BUFFER LINE POSITION
	INC	HL		;INCREMENT BUFFER PTR
	LD	A,(OBUFBACKCNT)	;GET BUFFER BYTE COUNT
	DEC	A		;BUFFER NOW FULL?
	JR	NZ,DOUT2	;CONTINUE IF NOT
	LD	DE,OBUF		;WRITE BUFFER TO DISK IF SO
	LD	C,1AH		;SET DMA ADDRESS
	CALL	BDOS
	LD	DE,FCBZ80	;WRITE BLOCK
	CALL	WRITEBLK
	LD	HL,OBUF		;RESET OUTPUT BUFFER PTR TO 1ST BYTE
	LD	A,80H		;RESET BUFFER BYTE COUNT
DOUT2:
	LD	(OBUFPTR),HL	;UPDATE OUTPUT BUFFER PTR
	LD	(OBUFBACKCNT),A	;UPDATE BUFFER BYTE COUNT
	POP	AF		;RESTORE REGS
	POP	BC
	POP	DE
	POP	HL
	RET
;
;  WRITE BLOCK WHOSE FCB IS PTED TO BY DE TO DISK
;
WRITEBLK:
	LD	C,15H	;CP/M BDOS WRITE BLOCK
	CALL	BDOS
	AND	A	;ERROR?
	RET	Z	;OK IF NONE
	LD	DE,ERR1	;ELSE PRINT ERROR MESSAGE AND ABORT
	JP	ENDERR
;
;  FILL LAST BLOCK WITH ^Z AND CLOSE OUTPUT FILE
;
CTRLZFILL:
	LD	A,(OBUFBACKCNT)	;GET REMAINING COUNT
	CP	80H		;FULL?
	JR	Z,CLOSEOUT	;CLOSE FILE THEN
	LD	A,1AH		;ELSE WRITE ^Z
	CALL	DOUTCHAR
	JR	CTRLZFILL
;
;  CLOSE OUTPUT FILE
;
CLOSEOUT:
	LD	DE,FCBZ80	;OUTPUT FCB
	LD	C,10H	;CLOSE FILE
	JP	BDOS
;
;  EXTRACT NEXT INPUT LINE FOR DISK FILE AND PLACE IT AS A 0-TERMINATED
;    STRING IN BUFFER 'INLN'
;
BUILDLINE:
	CALL	PDOT	;PRINT ACTIVITY DOT
	XOR	A	;A=FALSE OR 0
	LD	(INCMT),A	;TURN IN COMMENT FLAG OFF
	LD	(INQUOTE),A	;TURN IN QUOTE FLAG OFF
	LD	HL,INLN	;PT TO INLN BUFFER
	LD	B,80	;80 CHARS MAX
;
;  MAIN BUILD LOOP
;
NXTLCHAR:
	LD	DE,(IBUFPTR)	;PT TO NEXT CHAR IN FILE
	LD	A,(IBUFCNT)	;CHECK TO SEE IF BUFFER EMPTY
	CP	80H		;80H IF SO
	JR	NZ,PUTCHAR	;NOT EMPTY, SO PLACE CHAR IN LINE
	EXX			;SAVE REGS
	LD	DE,IBUFFER	;READ NEXT BLOCK FROM INPUT FILE
	LD	C,1AH		;SET DMA ADDRESS
	CALL	BDOS
	LD	DE,FCBASM	;READ THE BLOCK
	LD	C,14H
	CALL	BDOS
	DEC	A		;ERROR?
	JP	Z,ENDALL	;DONE IF SO (ASSUME EOF)
	EXX			;GET REGS BACK
	LD	DE,IBUFFER	;SET PTR TO 1ST BYTE OF BLOCK
	SUB	A		;CHAR COUNT = 0
;
;  PLACE CHAR PTED TO BE DE INTO INLN
;
PUTCHAR:
	LD	(IBUFCNT),A	;SAVE CHAR COUNT
	LD	A,(DE)		;GET CHAR
	INC	DE		;PT TO NEXT
	LD	(IBUFPTR),DE	;SAVE PTR
	PUSH	HL
	LD	HL,IBUFCNT	;INCR CHAR COUNT
	INC	(HL)
	POP	HL
	CALL	PCAPS		;CAPITALIZE CHAR OPTIONALLY
	LD	(HL),A		;SAVE CHAR FROM FILE INTO INLN
	CP	0DH		;END OF LINE?
	JR	Z,ENDBLINE	;DONE IF SO
	CP	9		;TAB EXPAND?
	JR	Z,CONTBLINE	;PROCESS AS NORMAL CHAR IF SO
	CP	' '	;LESS THAN <SP>?
	JR	C,NXTLCHAR	;DON'T PROCESS IF SO
CONTBLINE:
	DEC	B	;IS BUFFER FULL?
	INC	HL	;PT TO NEXT CHAR IN INLN BUFFER
	JR	NZ,NXTLCHAR	;CONTINUE PROCESSING IF NOT FULL
	INC	B	;WRITE OVER LAST CHAR FOR REST OF LINE
	DEC	HL
	JR	NXTLCHAR	;CONTINUE
;
;  OPTIONALLY CAPITALIZE CHAR IN A
;
PCAPS:
	PUSH	AF	;SAVE CHAR
	LD	A,(INCMT)	;IN A COMMENT?
	OR	A	;0=NO
	JR	NZ,PCAPS5	;DONE IF SO AND DON'T CAPITALIZE
	LD	A,(INQUOTE)	;IN A QUOTE?
	OR	A	;0=NO
	JR	NZ,PCAPS1	;DON'T CAPITALIZE IF SO
	POP	AF	;NOT IN COMMENT OR QUOTE, SO CAPITALIZE
	CALL	CAPS
	JR	PCAPS2
PCAPS1:
	POP	AF	;GET CHAR
PCAPS2:
	CP	';'	;COMING INTO A COMMENT?
	JR	NZ,PCAPS3
	PUSH	AF	;SAVE CHAR
	LD	A,0FFH	;SET INCMT FLAG
	LD	(INCMT),A
	JR	PCAPS5	;DONE
PCAPS3:
	PUSH	AF	;SAVE CHAR
	LD	A,(INQUOTE)	;IN A QUOTE?
	OR	A	;0=NO
	JR	Z,PCAPS4
	POP	AF	;GET CHAR -- WE ARE IN A QUOTE
	PUSH	AF	;SAVE IT AGAIN
	CP	''''	;ARE WE LEAVING THE QUOTE?
	JR	NZ,PCAPS5
	XOR	A	;A=0
	LD	(INQUOTE),A	;YES, SO SET NOT IN QUOTE
	JR	PCAPS5
PCAPS4:
	POP	AF	;GET CHAR
	PUSH	AF	;SAVE CHAR ONE LAST TIME
	CP	''''	;COMING INTO A QUOTE?
	JR	NZ,PCAPS5
	LD	A,0FFH	;SET INQUOTE FLAG
	LD	(INQUOTE),A
PCAPS5:
	POP	AF	;GET CHAR
	RET		;DONE
;
;  STORE ENDING <LF> AND <NULL>
;
ENDBLINE:
	INC	HL		;PT TO NEXT POSITION
	LD	(HL),0AH	;STORE <LF>
	INC	HL
	LD	(HL),0		;STORE <NULL>
	LD	(IBUFPTR),DE	;SAVE INPUT FILE PTR
;
;  IF LINE STARTS WITH AN ASTERISK (COMMENT LINE), MAKE IT START WITH A
;    SEMICOLON
;
	LD	A,(INLN)	;LOOK AT FIRST CHAR
	CP	'*'		;ASTERISK?
	JR	NZ,ENDBL1
	LD	A,';'		;REPLACE WITH SEMICOLON
	LD	(INLN),A
;
;  CHECK FOR EMPTY LINE AND JUST OUTPUT NEW LINE IF SO; ELSE RETURN
;
ENDBL1:
	LD	A,B		;LINE EMPTY?
	SUB	80		;START OVER IF SO
	RET	NZ		;DONE IF NOT EMPTY
	LD	A,0DH		;OUTPUT <CR> <LF> TO FILE FOR EMPTY LINE
	CALL	DOUTCHAR
	LD	A,0AH
	CALL	DOUTCHAR
	JP	BUILDLINE	;DO NEXT LINE
;
;  CAPITALIZE CHAR IN A
;
CAPS:
	AND	7FH		;MASK OUT MSB
	CP	61H		;DO NOTHING IF LESS THAN SMALL A
	RET	C
	CP	7AH+1		;CAP IF BETWEEN SMALL A AND Z, RESP
	RET	NC
	AND	5FH		;CAPITALIZE
	RET
;
;  END OF PROCESSING
;
ENDALL:
	CALL	CTRLZFILL	;FILL BUFFER WITH ^Z
	LD	DE,ERR5ON	;OPTIONALLY PRINT EACH ERROR MESSAGE IF SET
	CALL	PMSG
	LD	DE,XLT1ON
	CALL	PMSG
	LD	DE,XLT2ON
	CALL	PMSG
	LD	DE,XLT3ON
	CALL	PMSG
	LD	DE,XLT4ON
	CALL	PMSG
	LD	DE,MSG2
;
;  PRINT MESSAGE PTED TO BY DE WITH PRECEEDING <CRLF> AND FINISH UP
;
ENDERR:
	PUSH	DE	;SAVE PTR
	LD	DE,CRLFSTR	;PRINT <CRLF>
	CALL	PMSG
	POP	DE
	CALL	PMSG	;PRINT MESSAGE
	JP	WBOOT	;DONE
;
;  PRINT STRING PTED TO BY DE AND ENDING IN 0
;
PMSG:
	LD	A,(DE)	;GET CHAR
	AND	A	;ENDING 0?
	RET	Z	;DONE IF SO
	CALL	PCHAR	;OUTPUT CHAR IN A
	INC	DE	;PT TO NEXT CHAR
	JR	PMSG	;CONTINUE
;
;  PRINT CHAR IN A ON CON:
;
PCHAR:
	PUSH	AF	;SAVE REGS
	PUSH	BC
	PUSH	DE
	PUSH	HL
	LD	E,A	;CHAR IN E
	LD	C,2	;CON: OUTPUT
	CALL	BDOS
	POP	HL	;RESTORE REGS
	POP	DE
	POP	BC
	POP	AF
	RET

;
;  **** OP CODE TABLE, MESSAGE, AND BUFFER AREA ****
;

;
;  OP CODE TABLES
;
OCS1:
	DB	'ANI  AND  '
	DB	'CMA  CPL  '
	DB	'CMC  CCF  '
	DB	'CPI  CP   '
	DB	'HLT  HALT '
	DB	'JMP  JP   '
	DB	'ORI  OR   '
	DB	'RAL  RLA  '
	DB	'RAR  RRA  '
	DB	'RLC  RLCA '
	DB	'RRC  RRCA '
	DB	'STC  SCF  '
	DB	'SUI  SUB  '
	DB	'XRI  XOR  '
POPS:
	DB	'DB   DEFB '
	DB	'DS   DEFS '
	DB	'DW   DEFW '
	DB	'SET  DEFL '
NOXLT:
	DB	'ENT  ENTRY'
	DB	'NAM  NAME '
	DB	'RAM  DATA '
	DB	'ROG  REL  '
	DB	0		;END OF TABLE FOR OCS 1
OCS2:
	DB	'ANA  AND  '
	DB	'CMP  CP   '
	DB	'DCR  DEC  '
	DB	'INR  INC  '
	DB	'MVI  LD   '
	DB	'ORA  OR   '
	DB	'SUB  SUB  '
	DB	'XRA  XOR  '
	DB	0		;END OF TABLE FOR OCS 2
OCS3:
	DB	'DCX  DEC  '
	DB	'INX  INC  '
	DB	'LXI  LD   '
	DB	'POP  POP  '
	DB	'PUSH PUSH '
	DB	0		;END OF TABLE FOR OCS 3
OCS4:
	DB	'REQ  RNE  RLT  RGE  CEQ '
	DB	' CNE  CLT  CGE  JEQ  JNE '
	DB	' JLT  JGE  '
	DB	0		;END OF TABLE FOR OCS 4
RETS:
	DB	'RC   RNC  RZ   RNZ  RP  '
	DB	' RM   RPE  RPO  '
	DB	0		;END OF TABLE FOR RETS
CALLS:
	DB	'CC   CNC  CZ   CNZ  CP  '
	DB	' CM   CPE  CPO  '
	DB	0		;END OF TABLE FOR CALLS
JMPS:
	DB	'JC   JNC  JZ   JNZ  JP  '
	DB	' JM   JPE  JPO  '
	DB	0		;END OF TABLE FOR JMPS
OCS8:
	DB	'DAD  ADD  '
	DW	DO81
	DB	'ADD  ADD  '
	DW	DO82
	DB	'ADC  ADC  '
	DW	DO82
	DB	'SBB  SBC  '
	DW	DO82
	DB	'ADI  ADD  '
	DW	DO82
	DB	'ACI  ADC  '
	DW	DO82
	DB	'SBI  SBC  '
	DW	DO82
	DB	'IN   IN   '
	DW	DO83
	DB	'LDA  LD   '
	DW	DO83
	DB	'LDAX LD   '
	DW	DO84
	DB	'LHLD LD   '
	DW	DO85
	DB	'MOV  LD   '
	DW	DO86
	DB	'PCHL JP   '
	DW	DO88
	DB	'RST  RST  '
	DW	DO89
	DB	'SHLD LD   '
	DW	DO8A
	DB	'SPHL LD   '
	DW	DO8B
	DB	'STA  LD   '
	DW	DO8C
	DB	'OUT  OUT  '
	DW	DO8C
	DB	'STAX LD   '
	DW	DO8D
	DB	'XCHG EX   '
	DW	DO8E
	DB	'XTHL EX   '
	DW	DO8F
NOXLT2:
	DB	'IFC  IF   '
	DW	DO91
	DB	'ICL  *INCL'
	DW	DO92
	DB	'LST  LIST '
	DW	DO93
	DB	'MAC  MACRO'
	DW	DO94
	DB	0		;END OF TABLE FOR OCS8 AND NOXLT2
;
;  VARIOUS MESSAGES AND PROGRAM HEADER
;
HEADER:
	DB	'XLATE2 -- 8080-to-Z80 Translator, Version '
	DB	VERS/10+'0','.',(VERS MOD 10)+'0'
	DB	0DH,0AH,0
;  HELP MESSAGES
HMSG1:
	DB	0DH,0AH,0AH
	DB	'   XLATE2 translates 8080 assembly language source',0DH,0AH
	DB	'code into Zilog-Standard Z80 assembly language',0DH,0AH
	DB	'source code.  It is invoked by a command of the',0DH,0AH
	DB	'following form:',0DH,0AH,0AH
	DB	'      XLATE2 d:SRCFILE.typ d:destfile.typ',0DH,0AH,0AH
	DB	'   All characters in lower case are optional, and,',0DH,0AH
	DB	'if omitted, the following values are assumed:',0DH,0AH,0AH
	DB	'   . The Source File will have a type of ASM',0DH,0AH
	DB	'   . The Destination File will have the same name',0DH,0AH
	DB	'      as the Source File',0DH,0AH
	DB	'   . The Destination File will have a type of MAC',0DH,0AH,0AH
	DB	'Type <RETURN> to Continue - ',0
HMSG2:
	DB	0DH,0AH,0AH
	DB	'The following are examples of its use:',0DH,0AH,0AH
	DB	'      XLATE2 DEMO1 <-- Translates DEMO1.ASM to DEMO1.MAC'
	DB	0DH,0AH
	DB	'      XLATE2 DEMO1 DEMO2 <-- DEMO1.ASM to DEMO2.MAC'
	DB	0DH,0AH
	DB	'      XLATE2 DEMO1.TXT DEMO2.GGG <-- DEMO1.TXT to DEMO2.GGG'
	DB	0DH,0AH,0AH
	DB	'The following functions are also performed by XLATE2:'
	DB	0DH,0AH,0AH
	DB	'   . The M80 Pseudo-Ops .Z80 and ASEG will be inserted '
	DB	'at the front',0DH,0AH
	DB	'      of the MAC File',0DH,0AH
	DB	'   . The text in the Destination File will be '
	DB	'capitalized',0DH,0AH
	DB	'   . All comment lines beginning with an asterisk will '
	DB	'begin with',0DH,0AH
	DB	'      a semicolon instead',0DH,0AH,0AH
	DB	0
;  FILE NAME MESSAGES
PRFNM1:
	DB	'Source File: ',0
PRFNM2:
	DB	'    Destination File: ',0
;  FIRST TWO LINES OF MAC FILE
FHDR:
	DB	9,'.Z80',0DH,0AH	;USE ZILOG MNEMONICS
	DB	9,'ASEG',0DH,0AH	;USE ABSOLUTE SEGMENTS
	DB	0
ERR1:
	DB	'Output File Write Error',0DH,0AH,7,0
ERR2:
	DB	'No Source File Found',0DH,0AH,7,0
ERR3:
	DB	'No Directory Space',0DH,0AH,7,0
ERR4:
	DB	'Output File Already Exists -- Delete It and Continue (Y/N)? '
	DB	0
ERR4A:
	DB	'XLATE2 Aborting to CP/M',0
MSG2:
	DB	'XLATE2 Processing Complete',0
CRLFSTR:
	DB	0DH,0AH,0
;
;  VARIOUS ERROR MESSAGES
;
ERR5ON:
	DB	0	;THIS BYTE IS SET TO <CR> IF STRING ENABLED
ERR5:
	DB	0AH
	DB	'The following pseudo-ops '
	DB	'have been used in your source '
	DB	'and have not',0DH,0AH
	DB	'been '
	DB	'fully translated.  You must '
	DB	'complete the translation '
	DB	'using an editor.',0DH,0AH
	DB	9,'Original:',9,9,'Must Be Translated To:',0DH,0AH
	DB	0	;END OF STRING
XLT1ON:
	DB	0	;THIS BYTE IS SET TO <TAB> IF STRING ENABLED
XLT1:
	DB	'#ENDIF',9,9,9,'ENDIF',0DH,0AH,0
XLT2ON:
	DB	0	;THIS BYTE IS SET TO <TAB> IF STRINGENABLED
XLT2:
	DB	'ICL',9,9,9,'*INCLUDE',0DH,0AH,0
XLT3ON:
	DB	0	;THIS BYTE IS SET TO <TAB> IF STRING ENABLED
XLT3:
	DB	'LST  <operands>',9,9,'LIST <valid ASMB operands>'
	DB	0DH,0AH,0
XLT4ON:
	DB	0	;THIS BYTE IS SET TO <TAB> IF STRING ENABLED
XLT4:
	DB	'MAC <$parameters>',9,'MACRO <#parameters>',0DH,0AH
	DB	9,'[ ... ]',9,9,9,'MEND',0DH,0AH
	DB	9,'#macro-call',9,9,'macro-call',0DH,0AH,0
;
;  INPUT FILE FCB
;
FCBASM:
	DB	0,0,0,0,0,0,0,0,0,'ASM',0
	DB	0,0,0,0,0,0,0,0,0,0,0,0,0
	DB	0,0,0,0,0,0,0
;
;  OUTPUT FILE FCB
;
FCBZ80:
	DB	0,0,0,0,0,0,0,0,0,'MAC',0
	DB	0,0,0,0,0,0,0,0,0,0,0,0,0
	DB	0,0,0,0,0,0,0
;
;  BUFFERS
;
;  STACK AREA
	DS	128
;  CURRENT POSITION IN LINE OF OUTPUT BUFFER
OBUFLPOS:
	DS	1
;  COUNTER FOR EVERY 10 LINES
LCOUNT:
	DS	1
;  COUNTER FOR EVERY 60*10 LINES
NLCOUNT:
	DS	1
;  IN COMMENT FLAG -- 0 MEANS NOT
INCMT:
	DS	1
;  IN QUOTE FLAG -- 0 MEANS NOT
INQUOTE:
	DS	1
;  PTR TO TARGET OP CODE IN INPUT LINE
ILTOP:
	DS	2
;  OP CODE TO MATCH AGAINST
TARGOP:
	DS	5
;  PTR TO CURRENT POSITION IN CURRENT INPUT LINE
INLNPTR:
	DS	2
;  PTR TO CURRENT POSITION IN OUTPUT BUFFER (BLOCK)
OBUFPTR:
	DS	2
;  COUNT OF CHARS REMAINING IN OUTPUT BUFFER
OBUFBACKCNT:
	DS	1
;  OUTPUT BUFFER (BLOCK)
OBUF:
	DS	128
;  CURRENT INPUT LINE BUFFER
INLN:
	DS	80	;80 CHARS IN LINE
	DS	3	;3 EXTRA FOR <CR> <LF> <NULL>
;  PTR TO CURRENT POSITION IN INPUT BUFFER
IBUFPTR:
	DS	2
;  COUNT OF NUMBER OF CHARS LEFT IN INPUT BUFFER
IBUFCNT:
	DS	1
;  INPUT BUFFER (BLOCK)
IBUFFER:
	DS	128

	END
